﻿namespace Pottery.Module.Infrastructure
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Pottery.Model.Infrastructure;
    using Pottery.Module.Infrastructure.Interfaces;
    using Pottery.Module.Infrastructure.Models;

    /// <summary>
    /// Xml Storage
    /// </summary>
    public class XmlRepository : IRepository
    {
        #region IRepository Implementation

        public string GetStorageName<T>() where T : class
        {
            if (IsInitialized<T>())
                return m_FilesNames[typeof(T)].FileName;

            return null;
        }

        public bool IsInitialized<T>() where T : class
        {
            return m_FilesNames.ContainsKey(typeof(T)) && m_FilesNames[typeof(T)] != null;
        }

        public void Initialize<T>(string connectionString) where T : class
        {
            if (!IsInitialized<T>())
            {
                m_FilesNames[typeof(T)] = new XmlStorage() { FileName = connectionString };
                m_FilesNames[typeof(T)].GetData<T>();
            }
        }

        public void Add<T>(T tableEntity) where T : class
        {
            if (IsInitialized<T>())
            {
                m_FilesNames[typeof(T)].GetData<T>();
                m_FilesNames[typeof(T)].Content.Add(tableEntity);
                m_FilesNames[typeof(T)].SaveChanges<T>();

                return;
            }

            throw new NotSupportedException("Entity type is not supported");
        }

        public void Update<T>(T tableEntity) where T : class
        {
            if (IsInitialized<T>())
            {
                m_FilesNames[typeof(T)].GetData<T>();
                int index = m_FilesNames[typeof(T)].Content.IndexOf(tableEntity);

                if (index > -1)
                    m_FilesNames[typeof(T)].Content[index] = tableEntity;
                else
                    throw new InvalidOperationException();

                m_FilesNames[typeof(T)].SaveChanges<T>();

                return;
            }

            throw new NotSupportedException("Entity type is not supported");
        }

        public void Delete<T>(T tableEntity) where T : class
        {
            if (IsInitialized<T>())
            {
                m_FilesNames[typeof(T)].GetData<T>();
                int index = m_FilesNames[typeof(T)].Content.IndexOf(tableEntity);

                if (index > -1)
                    m_FilesNames[typeof(T)].Content.RemoveAt(index);
                else
                    throw new InvalidOperationException();

                m_FilesNames[typeof(T)].SaveChanges<T>();

                return;
            }

            throw new NotSupportedException("Entity type is not supported");
        }

        public T Create<T>() where T : class
        {
            ///TODO:Create models            

            throw new NotSupportedException("Entity type is not supported");
        }

        public T Item<T, Key>(Key key) where T : class
        {
            if (IsInitialized<T>())
            {
                m_FilesNames[typeof(T)].GetData<T>();

                if (typeof(Key) == typeof(int))
                    return m_FilesNames[typeof(T)].Content[Convert.ToInt32(key)] as T;

                return null;
            }

            throw new NotSupportedException("Entity type is not supported");
        }

        public IQueryable<T> GetQuery<T>() where T : class
        {
            return Enumerate<T>().AsQueryable<T>();
        }

        public IEnumerable<T> Enumerate<T>() where T : class
        {
            if (IsInitialized<T>())
            {
                List<T> result = new List<T>();
                foreach (var item in m_FilesNames[typeof(T)].Content)
                {
                    result.Add(item as T);
                }
                return result;
            }

            throw new NotSupportedException("Entity type is not supported");
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool managedDispose)
        {
            if (m_Dispose)
                return;

            if (managedDispose)
            {
                ///TODO:maneger resources
            }

            m_FilesNames.Clear();

            m_Dispose = true;
        }

        #endregion

        #region My Xml Mock

        private class XmlStorage
        {
            #region Properties

            public string FileName
            {
                get { return m_FileName; }
                set { m_FileName = value; }
            }

            public List<object> Content
            {
                get { return m_Content; }
            }

            #endregion

            #region Methods

            /// <summary>
            /// Saves changes
            /// </summary>
            /// <typeparam name="T"></typeparam>
            public void SaveChanges<T>() where T : class
            {
                List<T> list = new List<T>();
                foreach (object item in m_Content)
                {
                    list.Add(item as T);
                }

                DataSerializerHelper.XmlWrite<List<T>>(list, m_FileName);
            }

            /// <summary>
            /// Gets data from storage
            /// </summary>
            /// <typeparam name="T"></typeparam>
            public void GetData<T>() where T : class
            {
                m_Content.Clear();
                m_Content.AddRange(DataSerializerHelper.XmlRead<List<T>>(m_FileName));
            }

            #endregion

            #region Fields

            private string m_FileName = default(string);
            private readonly List<object> m_Content = new List<object>();

            #endregion
        }

        #endregion

        #region Private Fields

        private readonly Dictionary<Type, XmlStorage> m_FilesNames = new Dictionary<Type, XmlStorage>();
        private bool m_Dispose = false;

        #endregion
    }
}
